﻿using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using TEngine;
using System;
using UnityEngine.EventSystems;

public class LoopStepScrollView : MonoBehaviour, IBeginDragHandler, IDragHandler
{
    [SerializeField] private Transform itemParent; //列表项的父级，将卡片生成到该物体下
    [SerializeField] private ButtonEx prevButton; //上一个按钮
    [SerializeField] private ButtonEx nextButton; //下一个按钮
    [SerializeField] private float interval = 400f; //卡片之间的间距

    Func<int> itemCountHandle;
    Func<int, string> itemPathHandle;
    Action<int, GameObject> refreshHandle;
    Action<int> selectedHandle;

    //生成的卡片列表
    private readonly List<LoopScrollViewItem> m_CardList = new List<LoopScrollViewItem>();
    //字典用于存储各位置对应的卡片层级和坐标
    private readonly Dictionary<int, LoopScrollViewData> m_CardInfo = new Dictionary<int, LoopScrollViewData>();

    private void Start()
    {

        //添加按钮点击事件
        if(nextButton)
        nextButton.AddClickEvent(OnNextButtonClick);
        if(prevButton)
        prevButton.AddClickEvent(OnPrevButtonClick);
    }

    public void Refresh(int selectedIndex)
    {
        //   Clear
        foreach(var i in m_CardList)
        {
            PoolManager.Instance.PushGameObject(i.gameObject);
            GameObject.Destroy(i);
        }
        m_CardList.Clear();

        var itemCount = itemCountHandle();
        for (int i = 0; i < itemCount; i++)
        {
            var instance = PoolManager.Instance.GetGameObject(itemPathHandle(i));
            instance.SetActive(true);
            instance.transform.SetParent(itemParent, false);

            var item = instance.AddComponent<LoopScrollViewItem>();
            item.Index = (i - selectedIndex < 0 ? i + itemCount - selectedIndex : i - selectedIndex);
            item.DataIndex = i;
            m_CardList.Add(item);
            //instance.name = i.ToString();
            refreshHandle(item.DataIndex, instance);
            //坐标位置
            (instance.transform as RectTransform).anchoredPosition3D = Vector3.right * interval
                * (item.Index <= itemCount / 2 ? item.Index : (item.Index - itemCount));
            //大小
            instance.transform.localScale = (item.Index == 0 ? 1.2f : 1f) * Vector3.one;

        }
        m_CardList.Sort((LoopScrollViewItem a, LoopScrollViewItem b) => { return a.Index.CompareTo(b.Index); });
        for (int i = 0; i < m_CardList.Count; i++)
        {
            var item = m_CardList[i];
            //层级关系
            if(i == 0)
                item.transform.SetSiblingIndex(itemParent.childCount - 1);
            else
                item.transform.SetSiblingIndex(item.Index <= itemCount / 2 ? 0 : itemParent.childCount - 2);
        }
        m_CardInfo.Clear();
        for (int i = 0; i < m_CardList.Count; i++)
        {
            var item = m_CardList[i];
            m_CardInfo.Add(item.Index, new LoopScrollViewData(item.transform.GetSiblingIndex(), (item.transform as RectTransform).anchoredPosition3D));
        }
    }

    public List<LoopScrollViewItem> GetItems()
    {
        return m_CardList;
    }
    public void SetItemSelectedFunc(Action<int> func)
    {
        selectedHandle = func;
    }
    // 指定列表元素个数的回调，列表刷新时调用 | Callback that specifies the number of list elements, called when the list is refreshed
    public void SetItemCountFunc(Func<int> func)
    {
        itemCountHandle = func;
    }    
    // 指定生成的prefab路径，每个item刷新时调用 | Specify the generated prefab path, which is called when each item is refreshed
    public void SetSpawnPrefabPath(Func<int, string> func)
    {
        itemPathHandle = func;
    }


    // 指定刷新方法的回调，每个item刷新时调用 | Specifies the callback of the refresh method, which is called when each item is refreshed
    public void SetRefreshFunc(Action<int, GameObject> func)
    {
        refreshHandle = func;
    }
    //下一个按钮点击事件
    private void OnNextButtonClick()
    {
        for (int i = 0; i < m_CardList.Count; i++)
        {
            var item = m_CardList[i];
            bool last = item.Index == m_CardList.Count / 2;
            int index = item.Index + 1;
            index = index >= m_CardList.Count ? 0 : index;
            item.Index = index;
            item.Move(m_CardInfo[index], last);
            if(index == 0)
            {
                if(selectedHandle != null)
                    selectedHandle(item.DataIndex);
            }
        }
    }
    //上一个按钮点击事件
    private void OnPrevButtonClick()
    {
        for (int i = 0; i < m_CardList.Count; i++)
        {
            var item = m_CardList[i];
            int index = item.Index - 1;
            index = index < 0 ? m_CardList.Count - 1 : index;
            item.Index = index;
            item.Move(m_CardInfo[index], false);
            if (index == 0)
            {
                selectedHandle(item.DataIndex);
            }
        }
    }
    Vector3 m_PressDownMousePos;
    public void OnBeginDrag(PointerEventData eventData)
    {
        m_PressDownMousePos = Input.mousePosition;
    }

    public void OnDrag(PointerEventData eventData)
    {
        var difference = Input.mousePosition.x - m_PressDownMousePos.x;

        for (int i = 0; i < m_CardList.Count; i++)
        {
            var item = m_CardList[i];

            var targetPosition = item.CacheAnchorPosition3d;
            targetPosition.x += difference;
            item.RectTransform.anchoredPosition3D = targetPosition;

        }
        //if (difference / (interval*0.5f))
        //{

        //}
    }
}



/// <summary>
/// /////////////////////////////////////////////////////////////////////////////////////////
/// </summary>



public class LoopScrollViewItem : MonoBehaviour
{
    private RectTransform rectTransform;
    private int index; //用于记录当前所在位置
    private int dataIndex; //用于记录当前所在位置
    private Vector3 cacheScale; //开始移动时的大小
    private Vector3 cacheAnchorPosition3d; //开始移动时的坐标
    private Vector3 targetAnchorPostion3D; //目标坐标
    private int targetSiblingIndex; //目标层级
    private bool isMoving; //是否正在移动标识
    private float timer; //计时
    private bool last; //是否为最右侧的那张卡片

    public RectTransform RectTransform { get => rectTransform; set => rectTransform = value; }
    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();
    }

    public int Index
    {
        get
        {
            return index;
        }
        set
        {
            if (index != value)
            {
                index = value;
            }
        }
    }

    public int DataIndex
    {
        get
        {
            return dataIndex;
        }
        set
        {
            dataIndex = value;
        }
    }

    public Vector3 CacheAnchorPosition3d { get => cacheAnchorPosition3d; set => cacheAnchorPosition3d = value; }

    private void Update()
    {
        if (isMoving)
        {
            timer += Time.deltaTime * 2f;
            timer = Mathf.Clamp01(timer);
            if (timer >= .2f)
            {
                transform.SetSiblingIndex(targetSiblingIndex);
            }
            rectTransform.anchoredPosition3D = Vector3.Lerp(cacheAnchorPosition3d, targetAnchorPostion3D, last ? 1f : timer);
            transform.localScale = Vector3.Lerp(cacheScale, (index == 0 ? 1.3f : 1f) * Vector3.one, last ? 1f : timer);
            if (timer == 1f)
            {
                isMoving = false;
            }
        }
    }

    public void Move(LoopScrollViewData data, bool last)
    {
        timer = 0f;
        targetAnchorPostion3D = data.AnchorPosition3D;
        targetSiblingIndex = data.SiblingIndex;
        cacheAnchorPosition3d = rectTransform.anchoredPosition3D;
        cacheScale = transform.localScale;
        isMoving = true;
        this.last = last;
    }
}

/// <summary>
/// /////////////////////////////////////////////////////////////////////////////////////////
/// </summary>

public class LoopScrollViewData
{
    public int SiblingIndex { get; private set; }

    public Vector3 AnchorPosition3D { get; private set; }

    public LoopScrollViewData(int siblingIndex, Vector3 anchorPosition3D)
    {
        SiblingIndex = siblingIndex;
        AnchorPosition3D = anchorPosition3D;
    }
}